home *** CD-ROM | disk | FTP | other *** search
/ Amiga Collections: Auge 4000 / Auge 4000 #54 (1991-04-07)(Amiga User Gruppe Einzugsgebiet 4000).zip / Auge 4000 #54 (1991-04-07)(Amiga User Gruppe Einzugsgebiet 4000).adf / PopUpMenu / Source / Main.c < prev    next >
C/C++ Source or Header  |  1991-04-07  |  14KB  |  489 lines

  1. #include "PopUpMenu.h"
  2. #include "Version.h"
  3.  
  4. #define REPLYPORTNAME  "Reply"
  5. #define IMPDEVPORTNAME "ImpDev"
  6. #define TIMERPORTNAME  "Timer"
  7. #define QUITPORTNAME   "Quit"
  8. #define INPHANDLNAME   "PopUpMenu"
  9. #define SEMAPHORENAME  "PopUpMenu"
  10.  
  11. #define POPUPMSG       "\x9B0;33mPopUpMenu\x9B0m "
  12. #define KILLMSG        "removed.\n"
  13. #define STARTMSG       "installed.\n\xA9 Martin Adrian 1990\n"
  14. #define FAILMSG        "failed.\n"
  15.  
  16. /* Let the text stay for 3s if started from WorkBench */
  17. #define DELAYTIME      150
  18.  
  19. #define INPHANDLPRI    53
  20.  
  21. /* Must use kickstart 1.2 or higher */
  22. #define LIBVERSION     33
  23.  
  24. /* don't know how to find these in C */
  25. #define LVOSetMenuStrip   -0x108
  26. #define LVOClearMenuStrip -0x36
  27. #define LVOOnMenu      -0xc0
  28. #define LVOOffMenu      -0xb4
  29.  
  30. /* this is for errors in proto/exec.h */
  31. #undef RemSemaphore
  32. #pragma syscall RemSemaphore 25e 901
  33.  
  34. VOID InitPopUpMenu()
  35. {
  36.  
  37.   IMPORT struct DosLibrary     *DosBase;
  38.   IMPORT struct IntuitionBase  *IntuitionBase;
  39.   IMPORT struct GfxBase        *GfxBase;
  40.   IMPORT struct LayersBase     *LayersBase;
  41.  
  42.   IMPORT struct IOStdReq       *InputReqBlock;
  43.   IMPORT struct MsgPort        *TimerPort;
  44.   IMPORT struct timerequest    *TimerReqBlock;
  45.   IMPORT LONGBITS        TimerSignal;
  46.   IMPORT struct MsgPort        *ReplyPort;
  47.   IMPORT struct SignalSemaphore PopUpSemaphore;
  48.   IMPORT __fptr OldSetMenuStrip, OldClearMenuStrip, OldOnMenu, OldOffMenu;
  49.   IMPORT BPTR StdOut;
  50.   IMPORT BPTR PopUpSeg;
  51.  
  52.   struct MsgPort      *InputDevPort;
  53.   struct Interrupt    InputReqData;
  54.   struct SignalData   InputSignals;
  55.   LONG              MenuUpSigNum, MenuDownSigNum;
  56.   LONG              MouseMovedSigNum, SelectDownSigNum;
  57.  
  58.   geta4();   /* load global database */
  59.  
  60.   Write(StdOut,POPUPMSG,sizeof(POPUPMSG));
  61.  
  62.   /***********************************
  63.    * see if we are already installed *
  64.    ***********************************/
  65.   if (!(ReplyPort = FindPort(REPLYPORTNAME))) {
  66.     if (!(ReplyPort = MyCreatePort(REPLYPORTNAME)))
  67.       goto CleanUp13;
  68.   }
  69.   else {
  70.     /* yes, popupmenues already installed, tell running task to quit */
  71.     struct MsgPort *const QuitPort = MyCreatePort(QUITPORTNAME);
  72.     struct IntuiMessage *Message;
  73.  
  74.     if (QuitPort) {
  75.       if (Message = BuildIntuiMsg(QuitPort,QUITPOPUPMENU,NULL)) {
  76.     /* Send quitmessage */
  77.     PutMsg(ReplyPort, (struct Message *)Message);
  78.     /* Wait for reply */
  79.     WaitPort(QuitPort);
  80.     /* get rid of the message */
  81.     GetMsg(QuitPort);
  82.     FreeMem(Message,sizeof(struct IntuiMessage));
  83.  
  84.     WriteAndClose(KILLMSG, sizeof(KILLMSG));
  85.       }
  86.       MyDeletePort(QuitPort);
  87.     }
  88.     goto CleanUp13;
  89.   }
  90.  
  91.   /******************
  92.    * open libraries *
  93.    ******************/
  94.   if (!(IntuitionBase = (struct IntuitionBase *)
  95.             OpenLibrary("intuition.library", LIBVERSION)))
  96.     goto CleanUp12;
  97.   if (!(GfxBase       = (struct GfxBase *)
  98.             OpenLibrary("graphics.library", LIBVERSION)))
  99.     goto CleanUp11;
  100.   if (!(LayersBase    = (struct LayersBase *)
  101.             OpenLibrary("layers.library", LIBVERSION)))
  102.     goto CleanUp10;
  103.  
  104.   /************************
  105.    * Allocate our signals *
  106.    ************************/
  107.   if ((MenuUpSigNum     = AllocSignal(-1)) == -1)
  108.     goto CleanUp9;
  109.   if ((MenuDownSigNum   = AllocSignal(-1)) == -1)
  110.     goto CleanUp8;
  111.   if ((MouseMovedSigNum = AllocSignal(-1)) == -1)
  112.     goto CleanUp7;
  113.   if ((SelectDownSigNum = AllocSignal(-1)) == -1)
  114.     goto CleanUp6;
  115.  
  116.  /****************************************
  117.   * Build connection to the input.device *
  118.   ****************************************/
  119.   if (!(InputDevPort  = MyCreatePort(IMPDEVPORTNAME)))
  120.     goto CleanUp5;
  121.   if ((InputReqBlock = (struct IOStdReq *)
  122.                AllocMem(sizeof(struct IOStdReq),
  123.                MEMF_CLEAR | MEMF_PUBLIC)) == NULL)
  124.     goto CleanUp4;
  125.  
  126.   InputReqBlock->io_Message.mn_Node.ln_Type = NT_MESSAGE;
  127.   InputReqBlock->io_Message.mn_Length        = sizeof(struct IOStdReq);
  128.   InputReqBlock->io_Message.mn_ReplyPort    = InputDevPort;
  129.  
  130.   if (OpenDevice("input.device",0,(struct IORequest *)InputReqBlock,0))
  131.     goto CleanUp3;
  132.  
  133.   /****************************************
  134.    * Bulid connection to the timer.device *
  135.    ****************************************/
  136.   if (!(TimerPort = MyCreatePort(TIMERPORTNAME)))
  137.     goto CleanUp3x3;
  138.   TimerSignal = 1L << TimerPort->mp_SigBit;
  139.  
  140.   if (!(TimerReqBlock = (struct timerequest *)
  141.                AllocMem(sizeof(struct timerequest),
  142.                MEMF_CLEAR | MEMF_PUBLIC)))
  143.     goto CleanUp3x2;
  144.  
  145.   TimerReqBlock->tr_node.io_Message.mn_Node.ln_Type = NT_MESSAGE;
  146.   TimerReqBlock->tr_node.io_Message.mn_Length        = sizeof(struct timerequest);
  147.   TimerReqBlock->tr_node.io_Message.mn_ReplyPort    = TimerPort;
  148.  
  149.   if (OpenDevice(TIMERNAME,UNIT_VBLANK,(struct IORequest *)TimerReqBlock,0))
  150.     goto CleanUp3x1;
  151.  
  152.   /* Start Timer (just to be sure that at least one request is sent. */
  153.   /*          CheckIO doesn't work otherwise, i think) */
  154.  
  155.   QueTimer();
  156.  
  157.  
  158.   /********************
  159.    * Make a semaphore *
  160.    ********************/
  161.   PopUpSemaphore.ss_Link.ln_Name = /*SEMAPHORENAME*/ NULL;
  162.   PopUpSemaphore.ss_Link.ln_Pri  = 0;
  163. /*
  164.   AddSemaphore(&PopUpSemaphore);
  165. */
  166.   InitSemaphore(&PopUpSemaphore);
  167.   /**************************************************
  168.    * patch intuition functions to use our semaphore *
  169.    **************************************************/
  170.   if (!(OldSetMenuStrip = SetFunction((struct Library *)IntuitionBase,
  171.                       LVOSetMenuStrip,MySetMenuStrip)))
  172.     goto CleanUp2x4;
  173.   if (!(OldClearMenuStrip = SetFunction((struct Library *)IntuitionBase,
  174.                     LVOClearMenuStrip,MyClearMenuStrip)))
  175.     goto CleanUp2x3;
  176.   if (!(OldOnMenu = SetFunction((struct Library *)IntuitionBase,
  177.                 LVOOnMenu,MyOnMenu)))
  178.     goto CleanUp2x2;
  179.   if (!(OldOffMenu = SetFunction((struct Library *)IntuitionBase,
  180.                  LVOOffMenu,MyOffMenu)))
  181.     goto CleanUp2x1;
  182.  
  183.   /**********************************
  184.    * init data for the inputhandler *
  185.    **********************************/
  186.   InputSignals.PopUpMenuTask = FindTask(0);
  187.   InputSignals.MenuUpSig     = 1L << MenuUpSigNum;
  188.   InputSignals.MenuDownSig   = 1L << MenuDownSigNum;
  189.   InputSignals.MouseMovedSig = 1L << MouseMovedSigNum;
  190.   InputSignals.SelectDownSig = 1L << SelectDownSigNum;
  191.   InputSignals.Down         = FALSE;  /* menubutton is not down. (who cares) */
  192.  
  193.   /****************************
  194.    * startup the inputhandler *
  195.    ****************************/
  196.   InputReqData.is_Node.ln_Pri  = INPHANDLPRI;        /* must come before intuition */
  197.   InputReqData.is_Node.ln_Name = INPHANDLNAME;
  198.  
  199.   InputReqData.is_Data           = (APTR)&InputSignals;
  200.   InputReqData.is_Code           = (VOID *)PopUpHandler;
  201.  
  202.   InputReqBlock->io_Command = IND_ADDHANDLER;
  203.   InputReqBlock->io_Data    = (APTR)&InputReqData;
  204.  
  205.   DoIO((struct IORequest *)InputReqBlock);
  206.  
  207.   /***************************************
  208.    * tell the user that everything is ok *
  209.    ***************************************/
  210.   WriteAndClose(VERSION STARTMSG, sizeof(VERSION STARTMSG));
  211.  
  212.   PopUpMainLoop(&InputSignals);
  213.  
  214. CleanUp1:
  215.  
  216.   /* remove inputhandler */
  217.   InputReqBlock->io_Command = IND_REMHANDLER;
  218.   InputReqBlock->io_Data    = (APTR)&InputReqData;
  219.  
  220.   DoIO((struct IORequest *)InputReqBlock);
  221.  
  222.   /* restore intuition functions */
  223.   SetFunction((struct Library *)IntuitionBase,LVOOffMenu,OldOffMenu);
  224. CleanUp2x1:
  225.   SetFunction((struct Library *)IntuitionBase,LVOOnMenu,OldOnMenu);
  226. CleanUp2x2:
  227.   SetFunction((struct Library *)IntuitionBase,LVOClearMenuStrip,OldClearMenuStrip);
  228. CleanUp2x3:
  229.   SetFunction((struct Library *)IntuitionBase,LVOSetMenuStrip,OldSetMenuStrip);
  230. CleanUp2x4:
  231.  
  232.   /* remove semaphore */
  233. /*  RemSemaphore(&PopUpSemaphore);*/
  234.  
  235.   /* close timer.device */
  236.   CloseDevice((struct IORequest *)TimerReqBlock);
  237. CleanUp3x1:
  238.   FreeMem(TimerReqBlock,sizeof(struct timerequest));
  239. CleanUp3x2:
  240.   MyDeletePort(TimerPort);
  241. CleanUp3x3:
  242.  
  243.   /* close input.device */
  244.   CloseDevice((struct IORequest *)InputReqBlock);
  245. CleanUp3:
  246.   DeleteStdIO(InputReqBlock);
  247. CleanUp4:
  248.   MyDeletePort(InputDevPort);
  249. CleanUp5:
  250.  
  251.   /* Free allocated signals */
  252.   FreeSignal(SelectDownSigNum);
  253. CleanUp6:
  254.   FreeSignal(MouseMovedSigNum);
  255. CleanUp7:
  256.   FreeSignal(MenuDownSigNum);
  257. CleanUp8:
  258.   FreeSignal(MenuUpSigNum);
  259. CleanUp9:
  260.  
  261.   /* close libraries */
  262.   CloseLibrary((struct Library *)LayersBase);
  263. CleanUp10:
  264.   CloseLibrary((struct Library *)GfxBase);
  265. CleanUp11:
  266.   CloseLibrary((struct Library *)IntuitionBase);
  267. CleanUp12:
  268.   MyDeletePort(ReplyPort);
  269. CleanUp13:
  270.   if (StdOut)
  271.     WriteAndClose(FAILMSG,sizeof(FAILMSG));
  272.   if (PopUpSeg) {
  273.     /* if loaded from CLI unload us */
  274.     Forbid();
  275.     UnLoadSeg(PopUpSeg);
  276.   }
  277.   CloseLibrary((struct Library *)DOSBase);
  278. }
  279.  
  280. /***************************************
  281.  * WriteAndClose(Text,Length)          *
  282.  *                       *
  283.  * Input:                   *
  284.  *   Text   - Text to write to StdOut. *
  285.  *   Length                   *
  286.  ***************************************/
  287. VOID WriteAndClose(Text, Length)
  288.   STRPTR Text;
  289.   ULONG Length;
  290. {
  291.   IMPORT BPTR StdOut;
  292.  
  293.   Write(StdOut,Text,Length);
  294.   Delay(DELAYTIME);
  295.   Close(StdOut);
  296.   StdOut = NULL;
  297. }
  298.  
  299. /************************************************
  300.  * PopUpMainLoop(InputSignals,ReplyPort)        *
  301.  *                        *
  302.  * Input:                    *
  303.  *   InputSignals - Allocated signals.        *
  304.  *   ReplyPort      - Port for MENUVERIFY replies *
  305.  * Output:                    *
  306.  *   none                    *
  307.  ************************************************/
  308. VOID PopUpMainLoop(InputSignals)
  309.   struct SignalData *const InputSignals;
  310. {
  311.   IMPORT struct Window    *ActiveWindow;
  312.   IMPORT struct Screen    *Screen;
  313.   IMPORT struct Menu    *Menues;
  314.   IMPORT struct MsgPort *ReplyPort;
  315.  
  316.   const LONGBITS ReplySig    = 1L << (LONG)ReplyPort->mp_SigBit;
  317.  
  318.   WORD    NrOfMessages = 0;
  319.   WORD    Flags = 0;
  320.  
  321.   FOREVER {
  322.     const LONGBITS SignalBits = Wait(ReplySig |
  323.                      InputSignals->MenuUpSig |
  324.                      InputSignals->MenuDownSig);
  325.  
  326.     if (SignalBits & InputSignals->MenuUpSig) {
  327.       ActiveWindow = NULL;
  328.       Flags &= QUIT;
  329.     }
  330.  
  331.     if (SignalBits & ReplySig) {
  332.       struct IntuiMessage *Message;
  333.  
  334.       while (Message = (struct IntuiMessage *)GetMsg(ReplyPort)) {
  335.     if (Message->Class & MENUVERIFY) {
  336.       if (Message->IDCMPWindow == ActiveWindow)
  337.         if (Message->Code == MENUCANCEL)
  338.           Flags &= QUIT;   /* Verify not OK */
  339.         else
  340.           Flags |= VERIFYOK;
  341.       NrOfMessages--;
  342.       FreeMem(Message,sizeof(struct IntuiMessage));
  343.     }
  344.     else { /* Message->Class == QUITPOPUPMENU or some strange message */
  345.       ReplyMsg((struct Message *)Message); /* Message does not belong to this task */
  346.       Flags |= QUIT;
  347.     }
  348.  
  349.       } /* while */
  350.       if (NrOfMessages == 0) {
  351.     if (Flags & QUIT)
  352.       break;
  353.     if (Flags & VERIFYOK) {
  354.       PopUpMenu(InputSignals);
  355.       Flags = 0;
  356.     }
  357.       }
  358.     }
  359.  
  360.     if ((SignalBits & (InputSignals->MenuUpSig |
  361.                InputSignals->MenuDownSig)) == InputSignals->MenuDownSig) {
  362.       const LONG  Lock = LockIBase(0);
  363.  
  364.       ActiveWindow = IntuitionBase->ActiveWindow;
  365.  
  366.       if (ActiveWindow AND
  367.      !(ActiveWindow->Flags & RMBTRAP) AND
  368.      (ActiveWindow->MenuStrip)) {
  369.     Screen = ActiveWindow->WScreen;
  370.     NrOfMessages = SendMessage();
  371.     UnlockIBase(Lock);
  372.     if (NrOfMessages == 0)
  373.       PopUpMenu(InputSignals);
  374.     else
  375.       Flags |= VERIFYOK;
  376.       }
  377.       else
  378.     UnlockIBase(Lock);
  379.     }
  380.   } /* FOREVER */
  381. }
  382.  
  383. /*******************************************************
  384.  * SendMessage() - Send MENUVERIFY message             *
  385.  *  to all windows on screen with MENUVERIFY flag set. *
  386.  *  IBase must be locked!!                   *
  387.  * Input:                           *
  388.  *   none                           *
  389.  * Output:                           *
  390.  *   return    - Messages sent.                *
  391.  *******************************************************/
  392. WORD SendMessage()
  393. {
  394.   IMPORT struct Window    *const ActiveWindow;
  395.   IMPORT struct MsgPort *ReplyPort;
  396.   IMPORT struct Screen    *Screen;
  397.  
  398.   struct Window  *Window;
  399.   WORD     NrOfMessages = 0;
  400.  
  401.   Window = Screen->FirstWindow;
  402.   do {
  403.     if (Window->IDCMPFlags & MENUVERIFY) {
  404.       struct IntuiMessage *const Message =
  405.               BuildIntuiMsg(ReplyPort, MENUVERIFY,
  406.                  (Window == ActiveWindow) ? MENUHOT : MENUWAITING);
  407.       if (Message) {
  408.     CurrentTime(&Message->Seconds,&Message->Micros);
  409.     Message->IDCMPWindow = Window;
  410.  
  411.     PutMsg(Window->UserPort,(struct Message *)Message);
  412.     NrOfMessages++;
  413.       }
  414.     }
  415.   }
  416.   while (Window = Window->NextWindow);
  417.  
  418.   return (NrOfMessages);
  419. }
  420.  
  421. /***************************************
  422.  * BuildIntuiMsg(ReplyMsg,Class,Code)  *
  423.  *                       *
  424.  * Input:                   *
  425.  *   ReplyPort                   *
  426.  *   Class                   *
  427.  *   Code                   *
  428.  * Output:                   *
  429.  *   return    -  IntuiMessage           *
  430.  ***************************************/
  431. struct IntuiMessage *BuildIntuiMsg(ReplyPort,Class,Code)
  432.   struct MsgPort  *const ReplyPort;
  433.   ULONG   Class;
  434.   UWORD   Code;
  435. {
  436.   struct IntuiMessage *const Message =
  437.         AllocMem(sizeof(struct IntuiMessage),MEMF_PUBLIC | MEMF_CLEAR);
  438.  
  439.   if (Message) {
  440.     Message->ExecMessage.mn_Node.ln_Type = NT_MESSAGE;
  441.     Message->ExecMessage.mn_ReplyPort     = ReplyPort;
  442.     Message->ExecMessage.mn_Length     = sizeof(struct IntuiMessage) -
  443.                        sizeof(struct Message);
  444.     Message->Class = Class;
  445.     Message->Code  = Code;
  446.   }
  447.   return (Message);
  448. }
  449.  
  450. /*******************************
  451.  *  MyCreatePort(Name, Pri)    *
  452.  *  MyDeletePort(Port)         *
  453.  *                   *
  454.  *  Replacements for amiga.lib *
  455.  *******************************/
  456. struct MsgPort *MyCreatePort(Name)
  457.   STRPTR Name;
  458. {
  459.   UBYTE  SigBit;
  460.  
  461.   if ((SigBit = AllocSignal(-1)) != -1) {
  462.     struct MsgPort  *const Port = AllocMem(sizeof(struct MsgPort),
  463.                        MEMF_CLEAR | MEMF_PUBLIC);
  464.     if (Port) {
  465.       Port->mp_Node.ln_Name = Name;
  466.       Port->mp_Node.ln_Pri  = 0;
  467.       Port->mp_Node.ln_Type = NT_MSGPORT;
  468.       Port->mp_Flags        = PA_SIGNAL;
  469.       Port->mp_SigBit        = SigBit;
  470.       Port->mp_SigTask        = (struct Task *)FindTask(0);
  471.  
  472.       AddPort(Port);
  473.       return(Port);
  474.     }
  475.     else
  476.       FreeSignal((LONG)SigBit);
  477.   }
  478.   return(NULL);
  479. }
  480.  
  481. VOID MyDeletePort(Port)
  482.   struct MsgPort *const Port;
  483. {
  484.   RemPort(Port);
  485.   FreeSignal((LONG)Port->mp_SigBit);
  486.   FreeMem(Port,sizeof(struct MsgPort));
  487. }
  488.  
  489.